iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 26
1

本篇同步發文在個人Blog: 一袋.NET要扛幾樓?打造容器化的ASP.NET Core網站!系列文章 - (26) 建立購物車系統 - 9

1. 在WebMvc專案新增購物車服務的功能

1.1 新增購物車的服務類別

在WebMvc專案的Services新增CartService,並實作ICartService,主要是實作與購物車服務Api的串接:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WebMvc.Infrastructure;
using WebMvc.Models;
using WebMvc.Models.CartModels;

namespace WebMvc.Services
{
    public class CartService : ICartService
    {
        private readonly IOptionsSnapshot<AppSettings> _settings;
        private readonly IHttpClient _apiClient;
        private readonly string _remoteServiceBaseUrl;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly ILogger<CartService> _logger;

        public CartService(
            IOptionsSnapshot<AppSettings> settings,
            IHttpClient httpClient,
            ILogger<CartService> logger,
            IHttpContextAccessor httpContextAccessor)
        {
            _settings = settings;
            _remoteServiceBaseUrl = $"{_settings.Value.CartUrl}/api/v1/cart";
            _httpContextAccessor = httpContextAccessor;
            _apiClient = httpClient;
            _logger = logger;
        }

        public async Task AddItemToCartAsync(ApplicationUser user, CartItem product)
        {
            var cart = await GetCartAsync(user);
            _logger.LogDebug("user name" + user.Id);
            if (cart == null)
            {
                cart = new Cart()
                {
                    BuyerId = user.Id,
                    Items = new List<CartItem>()
                };
            }

            var cartItem = cart.Items
                .Where(p => p.ProductId == product.ProductId)
                .FirstOrDefault();

            if (cartItem == null)
            {
                cart.Items.Add(product);
            }
            else
            {
                cartItem.Quantity += 1;
            }

            await UpdateCartAsync(cart);
        }

        public async Task ClearCartAsync(ApplicationUser user)
        {
            var token = await GetUserTokenAsync();
            var cleanCartUri = ApiPaths.Cart.CleanCart(_remoteServiceBaseUrl, user.Id);
            _logger.LogDebug("Clean cart uri : " + cleanCartUri);
            var response = await _apiClient.DeleteAsync(cleanCartUri);
            _logger.LogDebug("cart cleaned");
        }

        public async Task<Cart> GetCartAsync(ApplicationUser user)
        {
            var token = await GetUserTokenAsync();
            _logger.LogInformation("we are in get cart and user id " + user.Id);
            _logger.LogInformation(_remoteServiceBaseUrl);

            var getCartUri = ApiPaths.Cart.GetCart(_remoteServiceBaseUrl, user.Id);
            _logger.LogInformation(getCartUri);
            var dataString = await _apiClient.GetStringAsync(getCartUri, token);
            _logger.LogInformation(dataString);
            var response = JsonConvert.DeserializeObject<Cart>(dataString.ToString()) ??
                new Cart()
                {
                    BuyerId = user.Id
                };
            return response;
        }

        public async Task<Cart> SetQuantitiesAsync(ApplicationUser user, Dictionary<string, int> quantities)
        {
            var cart = await GetCartAsync(user);
            cart.Items.ForEach(x =>
            {
                if (quantities.TryGetValue(x.Id, out var quantity))
                {
                    x.Quantity = quantity;
                }
            });

            return cart;
        }

        public async Task<Cart> UpdateCartAsync(Cart cart)
        {
            var token = await GetUserTokenAsync();
            _logger.LogDebug("Service url: " + _remoteServiceBaseUrl);
            var updateCartUri = ApiPaths.Cart.UpdateCart(_remoteServiceBaseUrl);
            _logger.LogDebug("Update cart url: " + updateCartUri);
            var response = await _apiClient.PostAsync(updateCartUri, cart, token);
            response.EnsureSuccessStatusCode();

            return cart;
        }
        private async Task<string> GetUserTokenAsync()
        {
            var context = _httpContextAccessor.HttpContext;
            return await context.GetTokenAsync("access_token");
        }
    }
}

1.2 修改ApiPaths類別

在WebMvc專案的Infrastructure修改ApiPaths.cs,增加購物車Api的Pattern:

namespace WebMvc.Infrastructure
{
    public static class ApiPaths
    {
        public static class Cart
        {
            public static string GetCart(string baseUri, string cartId)
            {
                return $"{baseUri}/{cartId}";
            }

            public static string UpdateCart(string baseUri)
            {
                return baseUri;
            }

            public static string CleanCart(string baseUri, string cartId)
            {
                return $"{baseUri}/{cartId}";
            }
        }

        public static class Catalog
        {
            public static string GetAllCatalogItems(string baseUri, int pageIndex, int pageSize, int? type)
            {
                string typeQueryString = "";
                if (type.HasValue)
                {
                    typeQueryString = type.Value.ToString();
                }

                return $"{baseUri}items?catalogTypeId={typeQueryString}&pageIndex={pageIndex}&pageSize={pageSize}";
            }

            public static string GetAllTypes(string baseUri)
            {
                return $"{baseUri}catalogTypes";
            }
        }
    }
}

1.3 修改IHttpClient和CustomHttpClient

在WebMvc專案的Infrastructure修改IHttpClient介面和CustomHttpClient類別,增加了JWT的token參數:

using System.Net.Http;
using System.Threading.Tasks;

namespace WebMvc.Infrastructure
{
    public interface IHttpClient
    {
        Task<string> GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer");
        Task<HttpResponseMessage> PostAsync<T>(string uri, T item, string authorizationToken = null, string authorizationMethod = "Bearer");
        Task<HttpResponseMessage> DeleteAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer");
        Task<HttpResponseMessage> PutAsync<T>(string uri, T item, string authorizationToken = null, string authorizationMethod = "Bearer");
    }
}
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace WebMvc.Infrastructure
{
    public class CustomHttpClient : IHttpClient
    {
        private HttpClient _client;
        private ILogger<CustomHttpClient> _logger;

        public CustomHttpClient( ILogger<CustomHttpClient> logger)
        {
            _client = new HttpClient();
            _logger = logger;
        }

        public async Task<HttpResponseMessage> DeleteAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer")
        {
            var requestMessage = new HttpRequestMessage(HttpMethod.Delete, uri);
            if (authorizationToken != null)
            {
                requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
            }

            return await _client.SendAsync(requestMessage);
        }

        public async Task<string> GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer")
        {
            var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri);

            if (authorizationToken != null)
            {
                requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
            }
            var response = await _client.SendAsync(requestMessage);
            return await response.Content.ReadAsStringAsync();
        }

        public async Task<HttpResponseMessage> PostAsync<T>(string uri, T item, string authorizationToken = null, string authorizationMethod = "Bearer")
        {
            return await DoPostPutAsync(HttpMethod.Post, uri, item, authorizationToken, authorizationMethod);
        }

        public async Task<HttpResponseMessage> PutAsync<T>(string uri, T item, string authorizationToken = null, string authorizationMethod = "Bearer")
        {
            return await DoPostPutAsync(HttpMethod.Put, uri, item, authorizationToken, authorizationMethod);
        }

        private async Task<HttpResponseMessage> DoPostPutAsync<T>(HttpMethod method, string uri, T item, string authorizationToken = null, string authorizationMethod = "Bearer")
        {
            if (method != HttpMethod.Post && method != HttpMethod.Put)
            {
                throw new ArgumentException("Value must be either post or put.", nameof(method));
            }

            var requestMessage = new HttpRequestMessage(method, uri)
            {
                Content = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json")
            };

            if (authorizationToken != null)
            {
                requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
            }

            var response = await _client.SendAsync(requestMessage);

            if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
            {
                throw new HttpRequestException();
            }

            return response;
        }
    }
}

上一篇
[Day25] 建立購物車系統 - 8
下一篇
[Day27] 建立購物車系統 - 10
系列文
一袋.NET要扛幾樓?打造容器化的ASP.NET Core網站!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言